package cn.nawang.ebeim.client.transfer;

import java.io.File;
import java.net.URI;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.nawang.ebeim.client.bean.ClientConfiguration;
import cn.nawang.ebeim.common.entity.FileInfo;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.QueryStringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.traffic.ChannelTrafficShapingHandler;

public class HttpDownloadClient {
  private static final Logger LOG = LoggerFactory.getLogger(HttpDownloadClient.class);
  private String host;
  private int port;
  private long downLength;
  // 多长时间未请求后，发送心跳
  private static final int WRITE_WAIT_SECONDS = 5;
  private static final int connLine = 1;

  private static volatile long CHANNEL_NUM = 0 ;
  private final static long MAX_CHANNEL_NUM = 20 ;

  public HttpDownloadClient(String host, int port) {
    this.host = host;
    this.port = port;
    if (CHANNEL_NUM >= MAX_CHANNEL_NUM){
      throw new RuntimeException("连接数超过限制,请稍后重试!");
    }else {
      CHANNEL_NUM ++ ;
    }
  }

  public void run(FileInfo info) throws Exception {
    final HttpDownloadClientHandler handler = new HttpDownloadClientHandler(info);
    EventLoopGroup group = new NioEventLoopGroup(connLine);
    try {
      Bootstrap b = new Bootstrap();
      b.group(group).channel(NioSocketChannel.class)
          .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
              ChannelPipeline pipeline = ch.pipeline();
              pipeline.addLast("codec", new HttpClientCodec());
              pipeline.addLast("ping", new IdleStateHandler(0, WRITE_WAIT_SECONDS, 0, TimeUnit.SECONDS));
              pipeline.addLast("inflater", new HttpContentDecompressor());
              pipeline.addLast("GLOBAL_TRAFFIC_SHAPING", new ChannelTrafficShapingHandler(ClientConfiguration.getWriteLimit(),ClientConfiguration.getReadLimit(),ClientConfiguration.getCheckInterval()));
              pipeline.addLast("chunkedWriter", new ChunkedWriteHandler());
              pipeline.addLast("handler", handler);
            }
          });
      // 发送下载请求
      formget(b, info);
    } finally {
      LOG.info(info.getDataId()+":文件签名：【"+info.getSignature()+"】版本号【"+info.getVersion()+"】--》【"+host+":"+port+"】客户端下载退出---------");
      group.shutdownGracefully();
      CHANNEL_NUM -- ;
      if(!handler.isConnect())
      {
        LOG.info("网络信号差，未建立连接！");
        throw new Exception("网络信号差，未建立连接！");
      }else if (!handler.isBool()) {
//        DbUpDownloadUtil.updateDownloadProcessBarCountByNid(-1, info.getNid());
        LOG.info("downLoadclient:"+info.getDataId()+":文件签名：【"+info.getSignature()+"】版本号【"+info.getVersion()+"】--》["+host+"]下载失败");
        throw new Exception("task:"+info.getDataId()+":文件签名：【"+info.getSignature()+"】版本号【"+info.getVersion()+"】--》["+host+"]下载失败");
        //TODO成功的话，下载进度条里面的“failedFile”字段+1
      }else{
        //TODO成功的话，下载进度条里面的“successFile”字段+1
      }
    }
  }
  private void formget(Bootstrap bootstrap, FileInfo info) throws Exception {
    downLength = 0;
    File f = HttpDownloadClientHandler.getFile(info);
    if (f.exists() && f.isFile()) {
      downLength = f.length();
    }
    Channel channel = bootstrap.connect(host, port).sync().channel();
    QueryStringEncoder encoder = new QueryStringEncoder("download");
    encoder.addParam("type", String.valueOf(info.getType()));
    encoder.addParam("version", info.getVersion());
    encoder.addParam("dataId", info.getDataId());
    encoder.addParam("signature", info.getSignature());
    encoder.addParam("signature", info.getSignature());
    encoder.addParam("downLength", String.valueOf(downLength));
    URI uriGet = new URI(encoder.toString());
    HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uriGet.toASCIIString());
    HttpHeaders headers = request.headers();
    headers.set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
    channel.writeAndFlush(request);
    channel.closeFuture().sync();
  }
}
